#!/bin/bash
#
#   AscentStream Platform Community Edition Installer
#   Copyright 2025 AscentStream Technology
#

# Set strict error handling
set -e

# Track last command for error reporting
track_last_command() {
    last_command=$current_command
    current_command=$BASH_COMMAND
}
trap track_last_command DEBUG

# Echo failed command for better error reporting
echo_failed_command() {
    local exit_code="$?"
    if [[ "$exit_code" != "0" ]]; then
        echo "'$last_command': command failed with exit code $exit_code."
    fi
}
trap echo_failed_command EXIT

# Global variables
ASP_PACKAGE_URL="https://asp-ce.tos-cn-beijing.volces.com/asp-community-edition-deploy-v20250714.tar.gz"
ASP_VERSION=$(echo "$ASP_PACKAGE_URL" | grep -o 'v[0-9]\{8\}' || echo "v20250707")
ASP_INSTALL_DIR="$HOME/asp-community"
ASP_TMP_DIR="$ASP_INSTALL_DIR/tmp"
ASP_PORT=8083

# ASCII Art for AscentStream Platform
print_ascii_art() {
    echo ''
    echo '    █████╗ ███████╗ ██████╗███████╗███╗   ██╗████████╗███████╗████████╗██████╗ ███████╗ █████╗ ███╗   ███╗'
    echo '   ██╔══██╗██╔════╝██╔════╝██╔════╝████╗  ██║╚══██╔══╝██╔════╝╚══██╔══╝██╔══██╗██╔════╝██╔══██╗████╗ ████║'
    echo '   ███████║███████╗██║     █████╗  ██╔██╗ ██║   ██║   ███████╗   ██║   ██████╔╝█████╗  ███████║██╔████╔██║'
    echo '   ██╔══██║╚════██║██║     ██╔══╝  ██║╚██╗██║   ██║   ╚════██║   ██║   ██╔══██╗██╔══╝  ██╔══██║██║╚██╔╝██║'
    echo '   ██║  ██║███████║╚██████╗███████╗██║ ╚████║   ██║   ███████║   ██║   ██║  ██║███████╗██║  ██║██║ ╚═╝ ██║'
    echo '   ╚═╝  ╚═╝╚══════╝ ╚═════╝╚══════╝╚═╝  ╚═══╝   ╚═╝   ╚══════╝   ╚═╝   ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═╝     ╚═╝'
    echo ''
    echo '                          ██████╗ ██████╗ ███╗   ███╗███╗   ███╗██╗   ██╗███╗   ██╗██╗████████╗██╗   ██╗'
    echo '                         ██╔════╝██╔═══██╗████╗ ████║████╗ ████║██║   ██║████╗  ██║██║╚══██╔══╝╚██╗ ██╔╝'
    echo '                         ██║     ██║   ██║██╔████╔██║██╔████╔██║██║   ██║██╔██╗ ██║██║   ██║    ╚████╔╝ '
    echo '                         ██║     ██║   ██║██║╚██╔╝██║██║╚██╔╝██║██║   ██║██║╚██╗██║██║   ██║     ╚██╔╝  '
    echo '                         ╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ╚═╝ ██║╚██████╔╝██║ ╚████║██║   ██║      ██║   '
    echo '                          ╚═════╝ ╚═════╝ ╚═╝     ╚═╝╚═╝     ╚═╝ ╚═════╝ ╚═╝  ╚═══╝╚═╝   ╚═╝      ╚═╝   '
    echo ''
    echo '                                              ███████╗██████╗ ██╗████████╗██╗ ██████╗ ███╗   ██╗'
    echo '                                              ██╔════╝██╔══██╗██║╚══██╔══╝██║██╔═══██╗████╗  ██║'
    echo '                                              █████╗  ██║  ██║██║   ██║   ██║██║   ██║██╔██╗ ██║'
    echo '                                              ██╔══╝  ██║  ██║██║   ██║   ██║██║   ██║██║╚██╗██║'
    echo '                                              ███████╗██████╔╝██║   ██║   ██║╚██████╔╝██║ ╚████║'
    echo '                                              ╚══════╝╚═════╝ ╚═╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝'
    echo ''
}

# Check operating system
check_os() {
    echo "Checking operating system..."
    case "$(uname)" in
        Linux*)
            echo "Linux detected."
            ;;
        Darwin*)
            echo "macOS detected."
            ;;
        *)
            echo "Unsupported operating system. ASP Community Edition supports Linux and macOS only."
            exit 1
            ;;
    esac
}

# Check if Docker is installed and running
check_docker() {
    echo "Checking Docker installation..."
    if ! command -v docker &> /dev/null; then
        echo "Docker is not installed. Please install Docker and try again."
        echo "Visit https://docs.docker.com/get-docker/ for installation instructions."
        exit 1
    fi
    
    echo "Checking if Docker daemon is running..."
    if ! docker info &> /dev/null; then
        echo "Docker daemon is not running. Please start Docker and try again."
        exit 1
    fi
    
    echo "Docker is installed and running."
}

# Check if Docker Compose is installed
check_docker_compose() {
    echo "Checking Docker Compose installation..."
    if ! docker compose version &> /dev/null; then
        echo "Docker Compose is not available. Please install Docker Compose and try again."
        echo "Visit https://docs.docker.com/compose/install/ for installation instructions."
        exit 1
    fi
    
    echo "Docker Compose is installed."
}

# Check if required ports are available
check_ports() {
    echo "Checking if required ports are available..."
    
    # Define all required ports
    local required_ports=(
        # From asp-console.yml
        3306  # MySQL
        8081  # ASP Console REST
        8083  # ASP Console Frontend (Web UI)
        
        # From asp-pulsar.yml
        6650  # Pulsar Broker
        8080  # Pulsar Web Service
        9092  # Pulsar Kafka Protocol
        9090  # Prometheus
    )
    
    # Function to check if a port is in use
    check_port_in_use() {
        local port=$1
        local in_use=false
        
        if command -v lsof &> /dev/null; then
            if lsof -i :$port &> /dev/null; then
                in_use=true
            fi
        elif command -v ss &> /dev/null; then
            if ss -tuln | grep -q ":$port "; then
                in_use=true
            fi
        elif command -v netstat &> /dev/null; then
            if netstat -tuln | grep -q ":$port "; then
                in_use=true
            fi
        elif command -v nc &> /dev/null; then
            if nc -z localhost $port &> /dev/null; then
                in_use=true
            fi
        else
            echo "Warning: Could not check if port $port is available. No port checking tools found (lsof, ss, netstat, nc)."
            return 0
        fi
        
        if [ "$in_use" = true ]; then
            echo "Error: Port $port is already in use. ASP Community Edition requires this port to be available."
            echo "Please stop any service using port $port and try again."
            return 1
        fi
        
        return 0
    }
    
    # Check all required ports
    local port_check_failed=false
    for port in "${required_ports[@]}"; do
        echo "Checking port $port..."
        if ! check_port_in_use $port; then
            port_check_failed=true
        fi
    done
    
    if [ "$port_check_failed" = true ]; then
        echo "Port check failed. Please resolve the port conflicts before proceeding."
        exit 1
    fi
    
    echo "All required ports are available."
}

# Check system resources
check_resources() {
    echo "Checking system resources..."
    
    # Check available disk space (need at least 1GB)
    local available_space
    if [[ "$(uname)" == "Darwin" ]]; then
        available_space=$(df -m $HOME | tail -1 | awk '{print $4}')
    else
        available_space=$(df -m $HOME | tail -1 | awk '{print $4}')
    fi
    
    if [[ $available_space -lt 1024 ]]; then
        echo "Warning: Less than 1GB of disk space available. ASP Community Edition may not function properly."
        echo "Available space: ${available_space}MB"
        echo "Recommended: At least 1GB"
    else
        echo "Sufficient disk space available: ${available_space}MB"
    fi
    
    # Check available memory
    local total_memory
    if [[ "$(uname)" == "Darwin" ]]; then
        total_memory=$(($(sysctl -n hw.memsize) / 1024 / 1024))
    else
        total_memory=$(($(grep MemTotal /proc/meminfo | awk '{print $2}') / 1024))
    fi
    
    if [[ $total_memory -lt 2048 ]]; then
        echo "Warning: Less than 2GB of RAM available. ASP Community Edition may not function properly."
        echo "Available memory: ${total_memory}MB"
        echo "Recommended: At least 2GB"
    else
        echo "Sufficient memory available: ${total_memory}MB"
    fi
}

# Download and extract ASP Community Edition package
download_and_extract() {
    echo "Preparing installation directory..."
    mkdir -p "$ASP_INSTALL_DIR"
    mkdir -p "$ASP_TMP_DIR"
    
    echo "Downloading ASP Community Edition package..."
    local asp_package_file="$ASP_TMP_DIR/asp-community-$ASP_VERSION.tar.gz"
    
    if command -v curl &> /dev/null; then
        curl --fail --location --progress-bar "$ASP_PACKAGE_URL" > "$asp_package_file"
    elif command -v wget &> /dev/null; then
        wget -q --show-progress -O "$asp_package_file" "$ASP_PACKAGE_URL"
    else
        echo "Neither curl nor wget found. Please install one of them and try again."
        exit 1
    fi
    
    echo "Extracting package..."
    # Create a temporary extraction directory
    local extract_tmp_dir="$ASP_TMP_DIR/extract_tmp"
    mkdir -p "$extract_tmp_dir"
    
    # Extract the archive to the temporary directory
    tar -xzf "$asp_package_file" -C "$extract_tmp_dir"
    
    # Move the contents of asp-ce directory directly to ASP_INSTALL_DIR
    echo "Moving files to installation directory..."
    mv "$extract_tmp_dir/asp-ce"/* "$ASP_INSTALL_DIR/"
    
    echo "Cleaning up temporary files and directories..."
    rm -f "$asp_package_file"
    rm -rf "$ASP_TMP_DIR"
}

# Install ASP Community Edition
install_asp() {
    echo "Installing ASP Community Edition..."
    cd "$ASP_INSTALL_DIR"
    
    # Simple wait function with fixed delay
    wait_fixed() {
        local service_name=$1
        local wait_seconds=${2:-15}
        
        echo "Waiting for $service_name to initialize ($wait_seconds seconds)..."
        sleep $wait_seconds
        echo "Continuing with next service..."
    }
    
    # Start MySQL service first
    echo "Starting MySQL service..."
    ./bin/asp start mysql
    if [ $? -ne 0 ]; then
        echo "Failed to start MySQL service. Installation aborted."
        exit 1
    fi
    wait_fixed "MySQL" 3
    
    # Start ASP Console service
    echo "Starting ASP Console service..."
    ./bin/asp start console
    if [ $? -ne 0 ]; then
        echo "Failed to start ASP Console service. Installation aborted."
        exit 1
    fi
    wait_fixed "ASP Console" 3
    
    # Start Pulsar cluster
    echo "Starting Pulsar cluster..."
    ./bin/asp start pulsar-cluster-1
    if [ $? -ne 0 ]; then
        echo "Failed to start Pulsar cluster. Installation aborted."
        exit 1
    fi
    wait_fixed "Pulsar cluster" 60  # Pulsar needs more time to initialize
    
    # Start Ping service
    echo "Starting Ping service..."
    ./bin/asp start ping
    if [ $? -ne 0 ]; then
        echo "Failed to start Ping service. Installation aborted."
        exit 1
    fi
    wait_fixed "Ping service" 3
    
    echo "All services started successfully."
}

# Check if ASP Community Edition is running
check_asp_status() {
    echo "Checking ASP Community Edition status..."
    
    # Wait for services to be up (max 60 seconds)
    local max_attempts=12
    local attempt=1
    local success=false
    
    echo "Waiting for services to start..."
    while [ $attempt -le $max_attempts ]; do
        echo "Checking service status (attempt $attempt/$max_attempts)..."
        
        if docker ps | grep -q "asp-console-front"; then
            if curl -s -o /dev/null -w "%{http_code}" http://localhost:$ASP_PORT | grep -q "200\|301\|302"; then
                success=true
                break
            fi
        fi
        
        sleep 5
        attempt=$((attempt + 1))
    done
    
    if [ "$success" = true ]; then
        echo "ASP Community Edition is running successfully!"
        return 0
    else
        echo "ASP Community Edition services did not start properly."
        echo "Please check the logs using 'docker logs asp-console-front' or 'docker logs asp-console-rest'."
        return 1
    fi
}

# Get console password from key file
get_console_password() {
    local password_file="$ASP_INSTALL_DIR/data/platform/asp_console_key.txt"
    if [ -f "$password_file" ]; then
        local password=$(grep "console_login_password:" "$password_file" | awk '{print $2}')
        if [ -n "$password" ]; then
            echo "$password"
            return 0
        fi
    fi

    return 1
}

# Print installation success message
print_success_message() {
    local ip_address
    if command -v hostname &> /dev/null; then
        ip_address=$(hostname -I 2>/dev/null | awk '{print $1}')
    fi
    
    if [ -z "$ip_address" ]; then
        ip_address="localhost"
    fi
    
    # Get console password
    local console_password=$(get_console_password)
    
    echo ""
    echo "======================================================================================================"
    echo "                          ASP Community Edition installed successfully!"
    echo "======================================================================================================"
    echo ""
    echo "Access your ASP Community Edition at: http://$ip_address:$ASP_PORT"
    echo ""
    echo "Login credentials:"
    echo "  Username: pulsar"
    echo "  Password: $console_password"
    echo ""
    echo "Service management:"
    echo "  Use ./bin/asp command to manage services (start, stop, restart, rm)"
    echo "  Run ./bin/asp help for a complete list of commands"
    echo "======================================================================================================"
    echo ""
}

# Main function
main() {
    print_ascii_art
    
    echo "Welcome to ASP Community Edition Installer"
    echo "This script will install ASP Community Edition on your system."
    echo ""
    
    # Run all checks
    check_os
    check_docker
    check_docker_compose
    check_ports
    check_resources
    
    echo ""
    echo "All checks passed. Starting installation..."
    echo ""
    
    # Install ASP Community Edition
    download_and_extract
    install_asp
    
    # Check installation status
    if check_asp_status; then
        print_success_message
    else
        echo "Installation completed but services may not be running correctly."
        echo "Please check the logs for more information."
        exit 1
    fi
}

# Run the main function
main
